home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / pgp23src.zip / SRC / LANGUAGE.C < prev    next >
C/C++ Source or Header  |  1993-05-09  |  9KB  |  415 lines

  1. /*
  2.  *    language.c - Foreign language translation for PGP
  3.  *    Finds foreign language "subtitles" for English phrases 
  4.  *    in external foriegn language text file.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "usuals.h"
  12. #include "fileio.h"
  13. #include "language.h"
  14. #include "pgp.h"
  15. #include "charset.h"
  16. #include "armor.h"
  17.  
  18. #define SUBTITLES_FILE    "language.txt"
  19. #define LANG_INDEXFILE    "language.idx"
  20.  
  21. #define    STRBUFSIZE        2048
  22.  
  23. char language[16] = "en";    /* The language code, defaults to English */
  24. static char    *strbuf;
  25. static char    lang[16];    /* readstr sets this to the language id of the msg it last read */
  26. static int    subtitles_available = 0;
  27. static int line = 0;
  28. /*    subtitles_available is used to determine if we know whether the special
  29.     subtitles_file exists.  subtitles_available has the following values:
  30.     0  = first time thru, we don't yet know if subtitles_file exists.
  31.     1  = we have already determined that subtitles_file exists.
  32.     -1 = we have already determined that subtitles_file does not exist.
  33. */
  34.  
  35. #define    NEWLINE        0
  36. #define    COMMENT        1
  37. #define    INSTRING    2
  38. #define    ESCAPE        3
  39. #define    IDENT        4
  40. #define    DONE        5
  41. #define    ERROR        6
  42. #define    ERR1        7
  43.  
  44. /* Look for and return a quoted string from the file.
  45.  * If nlabort is true, return failure if we find a blank line
  46.  * before we find the opening quote.
  47.  */
  48. static char    *
  49. readstr (FILE *f, char *buf, int nlabort)
  50. {    int        c, d;
  51.     char *p = buf;
  52.     int state = NEWLINE;
  53.     int i = 0;
  54.     
  55.     while ((c = getc(f)) != EOF)
  56.     {
  57.         if (c == '\r')
  58.             continue;
  59.         /* line numbers are only incremented when creating index file */
  60.         if (line && c == '\n')
  61.             ++line;
  62.         switch (state)
  63.         {
  64.             case NEWLINE:
  65.                 switch(c)
  66.                 {
  67.                     case '#': state = COMMENT; break;
  68.                     case '"': state = INSTRING; break;
  69.                     case '\n':
  70.                         if (nlabort)
  71.                         {    *buf = '\0';
  72.                             return(buf);
  73.                         }
  74.                     default:
  75.                         if (i == 0 && isalnum(c))
  76.                         {
  77.                             state = IDENT;
  78.                             lang[i++] = c;
  79.                             break;
  80.                         }
  81.                         if (!isspace(c))
  82.                         {
  83.                             fprintf(stderr, "language.txt:%d: syntax error\n", line);
  84.                             state = ERROR;
  85.                         }
  86.                 }
  87.                 break;
  88.             case COMMENT:
  89.                 if (c == '\n')
  90.                     state = NEWLINE;
  91.                 break;
  92.             case INSTRING:
  93.                 switch(c)
  94.                 {
  95.                     case '\\': state = ESCAPE; break;
  96.                     case '"': state = DONE; break;
  97.                     default: *p++ = c;
  98.                 }
  99.                 break;
  100.             case ESCAPE:
  101.                 switch (c)
  102.                 {
  103.                     case 'n':    *p++ = '\n';    break;
  104.                     case 'r':    *p++ = '\r';    break;
  105.                     case 't':    *p++ = '\t';    break;
  106.                     case 'e':    *p++ = '\033';    break;
  107.                     case 'a':    *p++ = '\007';    break;
  108.                     case '#':
  109.                     case '"':
  110.                     case '\\':    *p++ = c; break;
  111.                     case '\n':    break;
  112.                     case '0':
  113.                             d = 0;
  114.                             while ((c = fgetc(f)) >= '0' && c <= '7')
  115.                                 d = 8 * d + c - '0';
  116.                             *p++ = d;
  117.                             ungetc(c, f);
  118.                             break;
  119.                     default:
  120.                             fprintf(stderr, "language.txt:%d: illegal escape sequence: '\\%c'\n", line, c);
  121.                             break;
  122.                 }
  123.                 state = INSTRING;
  124.                 break;
  125.             case IDENT:        /* language identifier */
  126.                 if (c == ':') {
  127.                     state = NEWLINE;
  128.                     break;
  129.                 }
  130.                 if (c == '\n' && strncmp(lang, "No translation", 14) == 0)
  131.                 {
  132.                     i = 0;
  133.                     state = NEWLINE;
  134.                     break;
  135.                 }
  136.                 lang[i++] = c;
  137.                 if (i == 15 || !isalnum(c) && !isspace(c))
  138.                 {
  139.                     lang[i] = '\0';
  140.                     fprintf(stderr, "language.txt:%d: bad language identifier: '%s'\n", line, lang);
  141.                     state = ERROR;
  142.                     i = 0;
  143.                 }
  144.                 break;
  145.             case DONE:
  146.                 if (c == '\n')
  147.                 {
  148.                     lang[i] = '\0';
  149.                     *p = '\0';
  150.                     return(buf);
  151.                 }
  152.                 if (!isspace(c))
  153.                 {
  154.                     fprintf(stderr, "language.txt:%d: extra characters after '\"'\n", line);
  155.                     state = ERROR;
  156.                 }
  157.                 break;
  158.             case ERROR:
  159.                 if (c == '\n')
  160.                     state = ERR1;
  161.                 break;
  162.             case ERR1:
  163.                 state = (c == '\n' ? NEWLINE : ERROR);
  164.                 break;
  165.         }
  166.     }
  167.     if (state != NEWLINE)
  168.         fprintf(stderr, "language.txt: unexpected EOF\n");
  169.     return(NULL);
  170. }
  171.  
  172. #ifdef TEST
  173. main()
  174. {
  175.     char buf[2048];
  176.  
  177.     line = 1;
  178.     while (readstr(stdin, buf, 0)) {
  179.         printf("\nen: <%s>\n", buf);
  180.         while (readstr(stdin, buf, 1) && *buf != '\0')
  181.             printf("%s: <%s>\n", lang, buf);
  182.     }
  183.     exit(0);
  184. }
  185. #else
  186.  
  187. static struct indx_ent {
  188.     word32    crc;
  189.     long    offset;
  190. } *indx_tbl = NULL;
  191.  
  192. static int max_msgs = 0;
  193. static int nmsg = 0;
  194.  
  195. static FILE *langf;
  196.  
  197. static void init_lang(void);
  198.  
  199. static int make_indexfile(char *);
  200.  
  201. /*
  202.  * uses 24-bit CRC function from armor.c
  203.  */
  204. static word32
  205. message_crc(char *s)
  206. {
  207.     word32 crc = 0;
  208.  
  209.     while (*s)
  210.         crc = crcupdate(*s++, crc);
  211.     return(crc);
  212. }
  213.  
  214. /*
  215.  * lookup file offset in indx_tbl
  216.  */
  217. static long
  218. lookup_offset(word32 crc)
  219. {
  220.     int i;
  221.     
  222.     for (i = 0; i < nmsg; ++i)
  223.         if (indx_tbl[i].crc == crc)
  224.             return(indx_tbl[i].offset);
  225.     return(-1);
  226. }
  227.  
  228.  
  229. /*
  230.  * return foreign translation of s
  231.  */
  232. char *
  233. PSTR (char *s)
  234. {
  235.     long filepos;
  236.  
  237.     if (subtitles_available == 0)
  238.         init_lang();
  239.     if (subtitles_available < 0)
  240.         return(s);
  241.  
  242.     filepos = lookup_offset(message_crc(s));
  243.     if (filepos == -1)
  244.         return(s);
  245.     else
  246.     {
  247.         fseek(langf, filepos, SEEK_SET);
  248.         readstr(langf, strbuf, 1);
  249.     }
  250.  
  251.     if (strbuf[0] == '\0')
  252.         return(s);
  253.  
  254.     for (s = strbuf; *s; ++s)
  255.         *s = EXT_C(*s);
  256.     return(strbuf);
  257. }
  258.  
  259.  
  260. static struct {
  261.     long lang_fsize;    /* size of language.txt */
  262.     char lang[16];        /* language identifier */
  263.     int nmsg;            /* number of messages */
  264. } indx_hdr;
  265.  
  266.  
  267. /*
  268.  * initialize the index table: read it from language.idx or create
  269.  * a new one and write it to the index file. A new index file is
  270.  * created if the language set in config.pgp doesn't match the one
  271.  * in language.idx or if the size of language.txt has changed.
  272.  */
  273. static void
  274. init_lang()
  275. {
  276.     char indexfile[MAX_PATH];
  277.     char subtitles_file[MAX_PATH];
  278.     FILE *indexf;
  279.  
  280.     if (strcmp(language, "en") == 0)
  281.     {    subtitles_available = -1;
  282.         return;        /* use default messages */
  283.     }
  284.  
  285.     buildfilename (subtitles_file, SUBTITLES_FILE);
  286.     if ((langf = fopen(subtitles_file, FOPRTXT)) == NULL)
  287.     {
  288.         subtitles_available = -1;
  289.         return;
  290.     }
  291.     init_crc();
  292.     if ((strbuf = (char *) malloc(STRBUFSIZE)) == NULL)
  293.     {
  294.         fprintf(stderr, "Not enough memory for foreign subtitles\n");
  295.         fclose(langf);
  296.         subtitles_available = -1;
  297.         return;
  298.     }
  299.     buildfilename(indexfile, LANG_INDEXFILE);
  300.     if ((indexf = fopen(indexfile, FOPRBIN)) != NULL)
  301.     {
  302.         if (fread(&indx_hdr, 1, sizeof(indx_hdr), indexf) == sizeof(indx_hdr) &&
  303.             indx_hdr.lang_fsize == fsize(langf) &&
  304.             strcmp(indx_hdr.lang, language) == 0)
  305.         {
  306.             nmsg = indx_hdr.nmsg;
  307.             indx_tbl = (struct indx_ent *) malloc(nmsg * sizeof(struct indx_ent));
  308.             if (indx_tbl == NULL)
  309.             {
  310.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  311.                 fclose(indexf);
  312.                 fclose(langf);
  313.                 subtitles_available = -1;
  314.                 return;
  315.             }
  316.             if (fread(indx_tbl, sizeof(struct indx_ent), nmsg, indexf) != nmsg)
  317.             {
  318.                 free(indx_tbl);    /* create a new one */
  319.                 indx_tbl = NULL;
  320.             }
  321.         }
  322.         fclose(indexf);
  323.     }
  324.     if (indx_tbl == NULL && make_indexfile(indexfile) < 0)
  325.     {
  326.         fclose(langf);
  327.         subtitles_available = -1;
  328.     }
  329.     else
  330.         subtitles_available = 1;
  331. }
  332.  
  333.  
  334. static int
  335. make_indexfile(char *indexfile)
  336. {
  337.     FILE *indexf;
  338.     long filepos;
  339.     int total_msgs = 0;
  340.     char *res;
  341.  
  342.     if (verbose)    /* must be set in config.pgp */
  343.         fprintf(stderr, "Creating language index file '%s' for language \"%s\"\n",
  344.                 indexfile, language);
  345.     rewind(langf);
  346.     indx_hdr.lang_fsize = fsize(langf);
  347.     strncpy(indx_hdr.lang, language, 15);
  348.     init_crc();
  349.     line = 1;
  350.     nmsg = 0;
  351.     while (readstr(langf, strbuf, 0))
  352.     {
  353.         if (nmsg == max_msgs)
  354.         {
  355.             if (max_msgs)
  356.             {    max_msgs *= 2;
  357.                 indx_tbl = (struct indx_ent *) realloc(indx_tbl, max_msgs *
  358.                             sizeof(struct indx_ent));
  359.             }
  360.             else
  361.             {    max_msgs = 400;
  362.                 indx_tbl = (struct indx_ent *) malloc(max_msgs *
  363.                             sizeof(struct indx_ent));
  364.             }
  365.             if (indx_tbl == NULL)
  366.             {
  367.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  368.                 return(-1);
  369.             }
  370.         }
  371.         ++total_msgs;
  372.         indx_tbl[nmsg].crc = message_crc(strbuf);
  373.         if (lookup_offset(indx_tbl[nmsg].crc) != -1)
  374.             fprintf(stderr, "language.txt:%d: Message CRC not unique: \"%s\"\n",
  375.                     line, strbuf);
  376.         do
  377.         {
  378.             filepos = ftell(langf);
  379.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  380.         } while (res && strbuf[0] != '\0' && strcmp(language, lang) != 0);
  381.  
  382.         if (res == NULL)
  383.             break;
  384.         if (strbuf[0] == '\0')    /* No translation */
  385.             continue;
  386.  
  387.         indx_tbl[nmsg].offset = filepos;
  388.         ++nmsg;
  389.         do
  390.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  391.         while (res && strbuf[0] != '\0');
  392.     }
  393.     line = 0;
  394.     indx_hdr.nmsg = nmsg;
  395.     if (nmsg == 0)
  396.     {    fprintf(stderr, "No translations available for language \"%s\"\n\n",
  397.                 language);
  398.         return(-1);
  399.     }
  400.     if (verbose || total_msgs != nmsg)
  401.         fprintf(stderr, "%d messages, %d translations\n\n", total_msgs, nmsg);
  402.  
  403.     if ((indexf = fopen(indexfile, FOPWBIN)) == NULL)
  404.         fprintf(stderr, "Cannot create %s\n", indexfile);
  405.     else
  406.     {
  407.         fwrite(&indx_hdr, 1, sizeof(indx_hdr), indexf);
  408.         fwrite(indx_tbl, sizeof(struct indx_ent), nmsg, indexf);
  409.         if (ferror(indexf) || fclose(indexf))
  410.             fprintf(stderr, "error writing %s\n", indexfile);
  411.     }
  412.     return(0);
  413. }
  414. #endif /* TEST */
  415.